// Copyright (C) 2011 and onwards Noam Shazeer and Georges Harik

#include "allocator.h"

#ifndef _HASHTHING_H_
#define _HASHTHING_H_

// Is this thing a well-formed hashtable? (an marray of length 3n)
bool IsHash(Thing h);
bool IsMutableHash(Thing h);
inline int64 HashCapacity(Thing h) { return h.ArraySize() / 3; }

// For all future functions, we assume that h is well-formed and mutable 
//   if need be, and that all indices are in range. 

Thing & HashStatus(Thing h, Thing pos);
Thing & HashKey(Thing h, Thing pos);
Thing & HashValue(Thing h, Thing pos);

// returns the position where the key is or could be inserted.
Thing HashFind(Thing h, Thing key, ThreadAllocator *a);

// returns value, or default_value if not found. 
Thing HashLookDefault(Thing h, Thing key, 
		      Thing default_value, ThreadAllocator *a);

void HashSet(Thing h, Thing key, Thing value, ThreadAllocator *a);

void HashDelete(Thing h, Thing key, ThreadAllocator *a);

void GrowHash(Thing h, ThreadAllocator *a);

struct HashIterator {
public: 
  HashIterator(Thing h);
  Thing GetKey() { return HashKey(h_, Thing::MakeInteger(pos_)); }
  Thing GetValue() { return HashValue(h_, Thing::MakeInteger(pos_)); }
  void operator++() { pos_++; AdvanceToNextPresent(); }
  bool AtEnd() { return (pos_ == HashCapacity(h_));}

  // increases pos_ to point to next present position. 
  void AdvanceToNextPresent(); 
  Thing GetStatus() { return HashStatus(h_, Thing::MakeInteger(pos_)); }
  
  Thing h_;
  int64 pos_;
};


#endif
